#ifndef INTERVAL_TESTS_HPP
#define INTERVAL_TESTS_HPP

#include "utils/intervals.hpp"
#include <boost/test/test_tools.hpp>
#include <vector>

namespace utils
{

template< class T, class Traits = interval_traits< T> >
class interval_test_fixture_base
{
public:
	typedef interval_set< T, Traits> interval_set_type;
	typedef typename interval_set_type::interval_type interval_type;

	interval_test_fixture_base( 
		const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8, const T& v9, const T& v10, 
		const T& v11, const T& v12, const T& v13, const T& v14, const T& v15, const T& v16, const T& v17, const T& v18, const T& v19, const T& v20)
	{
		BOOST_REQUIRE( Traits::less( v1, v2));
		BOOST_REQUIRE( Traits::less( v2, v3));
		BOOST_REQUIRE( Traits::less( v3, v4));
		BOOST_REQUIRE( Traits::less( v4, v5));
		BOOST_REQUIRE( Traits::less( v5, v6));
		BOOST_REQUIRE( Traits::less( v6, v7));
		BOOST_REQUIRE( Traits::less( v7, v8));
		BOOST_REQUIRE( Traits::less( v8, v9));
		BOOST_REQUIRE( Traits::less( v9, v10));
		BOOST_REQUIRE( Traits::less( v10, v11));
		BOOST_REQUIRE( Traits::less( v11, v12));
		BOOST_REQUIRE( Traits::less( v12, v13));
		BOOST_REQUIRE( Traits::less( v13, v14));
		BOOST_REQUIRE( Traits::less( v14, v15));
		BOOST_REQUIRE( Traits::less( v15, v16));
		BOOST_REQUIRE( Traits::less( v16, v17));
		BOOST_REQUIRE( Traits::less( v17, v18));
		BOOST_REQUIRE( Traits::less( v18, v19));
		BOOST_REQUIRE( Traits::less( v19, v20));
		values_.push_back( v1); 
		values_.push_back( v2);
		values_.push_back( v3);
		values_.push_back( v4);
		values_.push_back( v5);
		values_.push_back( v6);
		values_.push_back( v7);
		values_.push_back( v8);
		values_.push_back( v9);
		values_.push_back( v10);
		values_.push_back( v11);
		values_.push_back( v12);
		values_.push_back( v13);
		values_.push_back( v14);
		values_.push_back( v15);
		values_.push_back( v16);
		values_.push_back( v17);
		values_.push_back( v18);
		values_.push_back( v19);
		values_.push_back( v20);
	}

	/// \brief It prepares the first test interval, in the range [v[1], v[3]).
	void prepare_first_interval( interval_set_type& is)
	{
		is.merge( values_[1], values_[3]);
	}

	/// \brief It prepares the second test interval, in the range [v[5],v[7]).
	void prepare_second_interval( interval_set_type& is)
	{
		is.merge( values_[5], values_[7]);
	}

	std::vector< T> values_;
};

template< class T, class Traits = interval_traits< T> >
class interval_test_fixture: public interval_test_fixture_base< T, Traits>
{
public:
//	interval_test_fixture( const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8, const T& v9)
//		: interval_test_fixture_base< T, Traits>( v1, v2, v3, v4, v5, v6, v7, v8, v9) {}
};

template< class TestFixture>
struct check_helper
{
	typedef typename TestFixture::interval_type interval_type;
	typedef typename TestFixture::interval_set_type interval_set_type;
	typedef typename interval_set_type::value_type value_type;
	typedef typename interval_set_type::traits_type traits_type;

	static void check_equal_values( const value_type& op1, const value_type& op2)
	{
		BOOST_CHECK_EQUAL( op1, op2);
	}

	static void check_interval( const interval_type& i, const value_type& expectedStart, const value_type& expectedEnd)
	{
		std::ostringstream os;
		value_type iBegin = traits_type::begin( i),
			iEnd = traits_type::end( i);
		os << "[" << expectedStart << ", " << expectedEnd << "] != [" << iBegin << ", " << iEnd << "]";
		BOOST_CHECK_MESSAGE( iBegin == expectedStart, os.str());
		BOOST_CHECK_MESSAGE( iEnd == expectedEnd, os.str());
	}

	static void check_interval_n( const typename interval_set_type::const_iterator& iter, std::size_t position, const value_type& expectedStart, const value_type& expectedEnd)
	{
		typename interval_set_type::const_iterator i = iter;
		std::advance( i, position);
		check_interval( *i, expectedStart, expectedEnd);
	}
};

#define CHECK_EQUAL_VALUE( OP1, OP2) check_helper< TestFixture>::check_equal_values( OP1, OP2)
#define CHECK_INTERVAL( ES, EE, I) check_helper< TestFixture>::check_interval( I, ES, EE)
#define CHECK_INTERVAL_N( ES, EE, I, N) check_helper< TestFixture>::check_interval_n( I, N, ES, EE)


template<> 
class interval_test_fixture< int, interval_traits< int> >: public interval_test_fixture_base< int, interval_traits< int> >
{
public:
	interval_test_fixture()
		: interval_test_fixture_base< int, interval_traits< int> >( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) {}
};

} // namespace utils

#endif // INTERVAL_TESTS_HPP
